﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Text;

namespace EpubSqueaker
{
	public static class XmlTools
	{
		/// <summary>
		/// "Convert" the specified XML 1.1 file to an XML 1.0 file at the specified path
		/// by updating the XML header. (This does no validation or conversion of other
		/// XML 1.0-invalid semantics.)
		/// </summary>
		/// <param name="xml11Path">Path to the XML 1.1 file.</param>
		/// <param name="xml10Path">Path to the XML 1.0 file.</param>
		public static bool ConvertXml11ToXml10(string xml11Path, string xml10Path)
		{
			// TODO: Update this to use our streamy piece below.

			bool validInput = true;

			// Open the file, and prep our list that will be used to build output.
			List<String> outputXmlBuilder = new List<String>();
			using (StreamReader inputXml = new StreamReader(xml11Path))
			{
				// Check to see if this is a valid file. If it is, load it into the list. If not, bail.
				string lineInput = inputXml.ReadLine();
				if (lineInput.Trim().Substring(0, 19) != "<?xml version=\"1.1\"")
				{
					validInput = false;
				}

				// Need to assemble the XML file in memory, in case input/output files are the same.
				outputXmlBuilder.Add("<?xml version=\"1.0\"" + lineInput.TrimStart().Substring(19));
				while ((lineInput = inputXml.ReadLine()) != null)
				{
					outputXmlBuilder.Add(lineInput);
				}
				if (!validInput)
				{
					throw new ArgumentException("Input XML file is not a recognized XML 1.1 file", "xml11Path");
				}
			}

			// Write the updated file.
			using (StreamWriter outputXml = new StreamWriter(xml10Path))
			{
				foreach (string lineOutput in outputXmlBuilder)
				{
					outputXml.WriteLine(lineOutput);
				}
			}
			return validInput;
		}

		/// <summary>
		/// "Convert" the specified XML stream to an XML 1.0 stream by
		/// updating the XML header, if needed (This does no validation
		/// or conversion of other XML 1.0-invalid semantics.)
		/// </summary>
		/// <param name="xmlStream">Stream to convert if necessary</param>
		public static bool ConvertXml11ToXml10(Stream xmlStream)
		{
			if (xmlStream == null)
			{
				throw new ArgumentNullException("xmlStream");
			}
			else if (!xmlStream.CanRead)
			{
				throw new ArgumentException("Stream does not support reading", "xmlStream");
			}
			else if (!xmlStream.CanWrite)
			{
				throw new ArgumentException("Stream does not support writing", "xmlStream");
			}
			else if (!xmlStream.CanSeek)
			{
				throw new ArgumentException("Stream does not support seeking", "xmlStream");
			}

			// Save our current position, and reset to the start of the file.
			// (Our other code should be "good" and reset to the start of the
			// file already, this is for safety's sake.)
			bool updatedStream = false;
			var initPosition = xmlStream.Position;
			xmlStream.Seek(0, SeekOrigin.Begin);

			// The XML declaration, including version, is specced as being
			// the first 19 characters of the file. So we're going to cheat.
			var xmlReader = new StreamReader(xmlStream);
			var declaration = xmlReader.ReadToEnd();
			if (declaration.Substring(0, 19) == "<?xml version=\"1.1\"")
			{
				// Rewrite the line.
				xmlStream.Seek(0, SeekOrigin.Begin);
				var lineBuilder = new StringBuilder();
				lineBuilder.Append("<?xml version=\"1.0\"");
				lineBuilder.Append(declaration.Substring(19));
				var xmlWriter = new StreamWriter(xmlStream);
				xmlWriter.Write(lineBuilder.ToString());
				xmlWriter.Flush();

				updatedStream = true;
			}

			xmlStream.Seek(initPosition, SeekOrigin.Begin);
			return updatedStream;
		}
	}
}
